<?php
/**
    fbpost_common v0.1.2
    Copyright 2010 Markus Dolic (crowley@gmx.net)
    
    This file is part of the fbpost package. 
    
    fbpost is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version. 
    fbpost is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details. 
    You should have received a copy of the GNU General Public License
    along with fbpost. If not, see <http://www.gnu.org/licenses/>. 
**/


define('DEBUG', false);
#define('DEBUG', true);
if (DEBUG) {
    #error_reporting(E_ALL);
    error_reporting(E_ALL & ~E_NOTICE);
}

define("TABLE_PP_ADDONS", $pixelpost_db_prefix . "addons");
define("TABLE_FBPOST_CFG", $pixelpost_db_prefix . "fbpost_cfg");
define("TABLE_FBPOST_AUTH", $pixelpost_db_prefix . "fbpost_auth");
define("TABLE_FBPOST_LIKE_CFG", $pixelpost_db_prefix . "fbpost_like_cfg");


class FBConst
{
    public static $LIKE_LAYOUTS = array("standard", "button_count", "box_count");
    public static $LIKE_ACTIONS = array("like", "recommend");
    public static $LIKE_FONTS = array("arial", "lucida grande", "segoe ui", "tahoma", "trebuchet ms", "verdana");
    public static $LIKE_COLORSCHEMES = array("light", "dark");
    public static $LOCALES = array(
        'af_ZA' => 'Afrikaans', 
        'sq_AL' => 'Albanian', 
        'ar_AR' => 'Arabic', 
        'hy_AM' => 'Armenian', 
        'ay_BO' => 'Aymara', 
        'az_AZ' => 'Azeri', 
        'eu_ES' => 'Basque', 
        'be_BY' => 'Belarusian', 
        'bn_IN' => 'Bengali', 
        'bs_BA' => 'Bosnian', 
        'bg_BG' => 'Bulgarian', 
        'ca_ES' => 'Catalan', 
        'ck_US' => 'Cherokee', 
        'hr_HR' => 'Croatian', 
        'cs_CZ' => 'Czech', 
        'da_DK' => 'Danish', 
        'nl_NL' => 'Dutch', 
        'nl_BE' => 'Dutch (Belgi)', 
        'en_PI' => 'English (Pirate)', 
        'en_GB' => 'English (UK)', 
        'en_US' => 'English (US)', 
        'en_UD' => 'English (Upside Down)', 
        'eo_EO' => 'Esperanto', 
        'et_EE' => 'Estonian', 
        'fo_FO' => 'Faroese', 
        'tl_PH' => 'Filipino', 
        'fi_FI' => 'Finnish', 
        'fr_CA' => 'French (Canada)', 
        'fr_FR' => 'French (France)', 
        'gl_ES' => 'Galician', 
        'ka_GE' => 'Georgian', 
        'de_DE' => 'German', 
        'el_GR' => 'Greek', 
        'gn_PY' => 'Guaran', 
        'gu_IN' => 'Gujarati', 
        'he_IL' => 'Hebrew', 
        'hi_IN' => 'Hindi', 
        'hu_HU' => 'Hungarian', 
        'is_IS' => 'Icelandic', 
        'id_ID' => 'Indonesian', 
        'ga_IE' => 'Irish', 
        'it_IT' => 'Italian', 
        'ja_JP' => 'Japanese', 
        'jv_ID' => 'Javanese', 
        'kn_IN' => 'Kannada', 
        'kk_KZ' => 'Kazakh', 
        'km_KH' => 'Khmer', 
        'tl_ST' => 'Klingon', 
        'ko_KR' => 'Korean', 
        'ku_TR' => 'Kurdish', 
        'la_VA' => 'Latin', 
        'lv_LV' => 'Latvian', 
        'fb_LT' => 'Leet Speak', 
        'li_NL' => 'Limburgish', 
        'lt_LT' => 'Lithuanian', 
        'mk_MK' => 'Macedonian', 
        'mg_MG' => 'Malagasy', 
        'ms_MY' => 'Malay', 
        'ml_IN' => 'Malayalam', 
        'mt_MT' => 'Maltese', 
        'mr_IN' => 'Marathi', 
        'mn_MN' => 'Mongolian', 
        'ne_NP' => 'Nepali', 
        'se_NO' => 'Northern Smi', 
        'nb_NO' => 'Norwegian (bokmal)', 
        'nn_NO' => 'Norwegian (nynorsk)', 
        'ps_AF' => 'Pashto', 
        'fa_IR' => 'Persian', 
        'pl_PL' => 'Polish', 
        'pt_BR' => 'Portuguese (Brazil)', 
        'pt_PT' => 'Portuguese (Portugal)', 
        'pa_IN' => 'Punjabi', 
        'qu_PE' => 'Quechua', 
        'ro_RO' => 'Romanian', 
        'rm_CH' => 'Romansh', 
        'ru_RU' => 'Russian', 
        'sa_IN' => 'Sanskrit', 
        'sr_RS' => 'Serbian', 
        'zh_CN' => 'Simplified Chinese (China)', 
        'sk_SK' => 'Slovak', 
        'sl_SI' => 'Slovenian', 
        'so_SO' => 'Somali', 
        'es_LA' => 'Spanish', 
        'es_CL' => 'Spanish (Chile)', 
        'es_CO' => 'Spanish (Colombia)', 
        'es_MX' => 'Spanish (Mexico)', 
        'es_ES' => 'Spanish (Spain)', 
        'es_VE' => 'Spanish (Venezuela)', 
        'sw_KE' => 'Swahili', 
        'sv_SE' => 'Swedish', 
        'sy_SY' => 'Syriac', 
        'tg_TJ' => 'Tajik', 
        'ta_IN' => 'Tamil', 
        'tt_RU' => 'Tatar', 
        'te_IN' => 'Telugu', 
        'th_TH' => 'Thai', 
        'zh_HK' => 'Traditional Chinese (Hong Kong)', 
        'zh_TW' => 'Traditional Chinese (Taiwan)', 
        'tr_TR' => 'Turkish', 
        'uk_UA' => 'Ukrainian', 
        'ur_PK' => 'Urdu', 
        'uz_UZ' => 'Uzbek', 
        'vi_VN' => 'Vietnamese', 
        'cy_GB' => 'Welsh', 
        'xh_ZA' => 'Xhosa', 
        'yi_DE' => 'Yiddish', 
        'zu_ZA' => 'Zulu', 
    );
}


class FBApiException extends Exception
// from the official facebook PHP API (facebook.php)
{
    /**
    * The result from the API server that represents the exception information. 
    */
    protected $result;
    
    /**
    * Make a new API Exception with the given result.
    *
    * @param Array $result the result from the API server
    */
    public function __construct($result)
    {
        $this->result = $result;
        $code = isset($result['error_code']) ? $result['error_code'] : 0;
        $msg = isset($result['error'])
            ? $result['error']['message'] : $result['error_msg'];
        parent::__construct($msg, $code);
    }
    
    /**
    * Return the associated result object returned by the API server.
    *
    * @returns Array the result from the API server
    */
    public function getResult()
    {
        return $this->result;
    }
    
    /**
    * Returns the associated type for the error. This will default to
    * 'Exception' when a type is not available.
    *
    * @return String
    */
    public function getType()
    {
        return
            isset($this->result['error']) && isset($this->result['error']['type'])
            ? $this->result['error']['type']
            : 'Exception';
    }
    
    /**
    * To make debugging easier.
    *
    * @returns String the string representation of the error
    */
    public function __toString()
    {
        $str = $this->getType() . ': ';
        if ($this->code != 0) {
          $str .= $this->code . ': ';
        }
        return $str . $this->message;
    }
}


class FBProxy
{
    const GRAPH_URL = "https://graph.facebook.com";
    const OAUTH_URL = "https://graph.facebook.com/oauth/authorize";
    const TOKEN_URL = "https://graph.facebook.com/oauth/access_token";
    
    public static $certFilePath = "";
    
    function __construct()
    {
        $this->token = '';
        $result = mysql_query("SELECT token FROM " . TABLE_FBPOST_AUTH 
            . " LIMIT 1");
        if ($result !== false)
            $this->token = mysql_result($result, 0);
    }
    
    /**
    * Call a Facebook Graph API function. 
    * 
    * @param String $path path of the function to call
    * @param String $method the HTTP request method (default: GET)
    * @param Array $args the function arguments
    * @return the decoded response
    * @throws FBApiException
    */
    function api($path, $args=array(), $method="GET")
    {
        if (!isset($args['access_token'])) {
            $args['access_token'] = $this->token;
        }
        $url = self::GRAPH_URL . $path;
        $response = FBProxy::httpReq($url, $args, $method);
        $result = json_decode($response, true);
        // raise Exception if API error occurred, otherwise return results
        if (is_array($result) && isset($result['error'])) {
            throw new FBApiException($result);
        }
        return $result;
    }
    
    /**
    * Performs an HTTP request using Curl. 
    * 
    * @param String $url URL to request
    * @param String $method the HTTP request method (default: GET)
    * @param Array $args the request arguments (which will be appended to the 
    *     URL for GET requests, or put in the request body for POST requests)
    * @return the response on success, FALSE on failure
    * @throws FBApiException
    */
    static function httpReq($url, $args=array(), $method="GET")
    {
        #echo "curl request: " . $path . "(" . print_r($args, true) . ")<br />";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // disable 'Expect: 100-continue' behavior to avoid delays
        curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));
        // define SSL certificate file if applicable
        if (FBProxy::$certFilePath != "")
            curl_setopt($ch, CURLOPT_CAINFO, FBProxy::$certFilePath);
        // set further options according to request method
        curl_setopt($ch, CURLOPT_URL, $url);
        if ($method == "GET") {
            curl_setopt($ch, CURLOPT_URL, 
                        $url . "?" . http_build_query($args, null, "&"));
        }
        else {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
        }
        // make request and handle response
        $response = curl_exec($ch);
        if ($response === false) {
            $e = new FBApiException(array(
                "error_code" => curl_errno($ch), 
                "error" => array(
                    "message" => curl_error($ch), 
                    "type" => "CurlException")));
            curl_close($ch);
            throw $e;
        }
        #echo "curl response: " . print_r($response, true) . "<br />";
        curl_close($ch);
        return $response;
    }
    
    /**
    * Retrieves an OAuth access token from Facebook. This is different 
    * from "regular" FB API functions in that
    * a) we do not have an access token yet (duh) and
    * b) it returns a plain string ("access_token=...") if successful, 
    *    but a JSON object in the failure case
    * 
    * @param String $app_id Facebook app ID
    * @param String $secret Facebook app secret
    * @param String $code verification string returned by Facebook in 
    *     the first OAuth step
    * @param String $redirect_uri the same redirect URI that was 
          supplied during the first OAuth step
    * @return the access token
    * @throws FBApiException
    */
    static function getToken($app_id, $secret, $code, $redirect_uri)
    {
        $args = array(
            "client_id" => $app_id, 
            "client_secret" => $secret, 
            "code" => $_GET['code'], 
            "redirect_uri" => $redirect_uri);
        $response = FBProxy::httpReq(FBProxy::TOKEN_URL, $args);
        if (strpos($response, "access_token=") === 0)
            return str_replace("access_token=", "", $response);
        else
            throw new FBApiException(json_decode($response, true));
    }
    
    function getProfiles()
    /**
    * Returns an assoc array of the authorized user's own profile and all profiles he is admin for 
    * (with IDs as keys and profile data arrays as values). Each profile data array contains an 
    * access_token that can be used to post to that profile as the profile itself (impersonation). 
    */
    {
        $ret = array();
        $me = $this->api("/me");
        $me["access_token"] = $this->token;
        $ret[$me["id"]] = $me;
        $accounts = $this->api("/me/accounts");
        foreach ($accounts["data"] as $adata) {
            $ret[$adata["id"]] = $adata;
        }
        return $ret;
    }
    
    function getProfile($profile_id)
    {
        $profiles = $this->getProfiles();
        return $profiles[$profile_id];
    }
}


/******************************************************************************
 * 
 * miscellaneous helper functions
 * 
 *****************************************************************************/

function getval($array, $key)
{
    return $array[$key];
}


function checkExtensions()
{
    if (!function_exists('curl_init')) {
        throw new Exception('fbpost requires the CURL PHP extension. ');
    }
    if (!function_exists('json_decode')) {
        throw new Exception('fbpost requires the JSON PHP extension. ');
    }
    return True;
}


function formatErrorMsg($msg)
{
    return "<div class='confirm'>Error: <br />{$msg}</div><br />";
}


function isAddonEnabled($name, $prefix="_fbpost/")
{
    $res = mysql_query("SELECT status FROM " . TABLE_PP_ADDONS 
        . " WHERE addon_name='$prefix$name' LIMIT 1");
    if ($res !== false and mysql_num_rows($res) > 0 
        and mysql_result($res, 0) == "on")
        return true;
    return false;
}


/******************************************************************************
 * 
 * common initialization for all fbpost addons
 * 
 *****************************************************************************/

if (isAddonEnabled("admin_fb_auth") or isAddonEnabled("admin_fb_sync")) {

    // create cfg table if it does not exist yet
    if (!mysql_query("SELECT * FROM " . TABLE_FBPOST_CFG . " LIMIT 1")) {
        mysql_query("CREATE TABLE IF NOT EXISTS " . TABLE_FBPOST_CFG . " (
                         `def_profile_id` VARCHAR(255), 
                         `def_sync_message` VARCHAR(4000), 
                         `cert_file_path` VARCHAR(8000)
                    )") or die(mysql_error());
        // insert default config record
    	mysql_query("INSERT INTO " . TABLE_FBPOST_CFG . 
                    " VALUES('', 'posted a new photo: ', '')") 
            or die(mysql_error()); 
    }

    // retrieve certificate file path from DB
    $result = mysql_query("SELECT cert_file_path FROM " . TABLE_FBPOST_CFG 
        . " LIMIT 1");
    if ($result !== false)
        FBProxy::$certFilePath = mysql_result($result, 0);
}
?>
